﻿using Nemerle.Collections;
using Nemerle.Text;
using Nemerle.Surround;
using Nemerle.Utility;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;

[assembly: DefineSurround("read_lock", true, locker.EnterReadLock(), locker.ExitReadLock())]
[assembly: DefineSurround("write_lock", true, locker.EnterWriteLock(), locker.ExitWriteLock())]

namespace MetadataReader.CCI
{
  public class ReadWriteHashtable[K,V] : Seq[KeyValuePair[K,V]]
  {
    private hashtable : Hashtable[K,V] = Hashtable();
    private locker    : ReaderWriterLockSlim = ReaderWriterLockSlim();
    
    public Item[key : K] : V
    {
      get
      {
        surroundwith (read_lock)
    	    hashtable[key]
      }
      
      set
      {
        surroundwith (write_lock)
    	    hashtable[key] = value;
      }
    }
    
    public Contains(key : K) : bool
    {
      surroundwith (read_lock)
    	  hashtable.ContainsKey(key)
    }
    
    public TryGetValue(key : K, val : out V) : bool
    {
      surroundwith (read_lock)
    	  hashtable.TryGetValue(key, out val)
    }
    
    public TryGetValue(key : K) : (V * bool)
    {
      surroundwith (read_lock)
    	  hashtable.TryGetValue(key)
    }
    
    public Add(key : K, value : V) : void
    {
      surroundwith (write_lock)
  	    hashtable.Add(key, value);
    }
    
    public AddRange(range : Seq[KeyValuePair[K,V]]) : void
    {
      surroundwith (write_lock)
  	  {
  	    foreach(kv in range)
  	      hashtable.Add(kv.Key, kv.Value);
  	  }
    }
    
    public AddRange(range : Seq[K*V]) : void
    {
      surroundwith (write_lock)
  	  {
  	    foreach(kv in range)
  	      hashtable.Add(kv);
  	  }
    }
    
    public Clear() : void
    {
      surroundwith (write_lock)
  	    hashtable.Clear();
    }
    
    
    #region System.Collections.IEnumerable
    
    GetEnumeratorNonGeneric() : System.Collections.IEnumerator
     implements System.Collections.IEnumerable.GetEnumerator
    {
    	GetEnumerator()
    }
    
    public GetEnumerator() : System.Collections.Generic.IEnumerator[KeyValuePair[K,V]]
    {
    	Enumerator(locker, hashtable)
    }
    
    private class Enumerator : IEnumerator[KeyValuePair[K,V]]
    { 
      private mutable _disposed : bool;
      private _locker : ReaderWriterLockSlim;
      private _enumerator : IEnumerator[KeyValuePair[K,V]];
      public this(locker : ReaderWriterLockSlim, enumerable : IEnumerable[KeyValuePair[K,V]])
      {
        _locker = locker;
        locker.EnterReadLock();
        _enumerator = enumerable.GetEnumerator();
      }
      protected override Finalize() : void
      {
        Dispose();
      }
      
      public Dispose() : void
      {
        unless (_disposed)
        {
          _disposed = true;
          _enumerator.Dispose();
          _locker.ExitReadLock();
        }
      }

      public MoveNext() : bool
      {
      	_enumerator.MoveNext()
      }
      
      public Reset() : void
      {
      	_enumerator.Reset()
      }
      
      public Current : KeyValuePair[K,V]
      {
      	get
      	{
      		_enumerator.Current
      	}
      }
    }
    
    #endregion    
  }
}
